package com.bytz.modules.cms.reseller.service.impl;

import cn.hutool.core.util.BooleanUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.bytz.common.system.base.service.impl.AbstractCrudService;
import com.bytz.common.util.mentity.EntityMergeInfoV2;
import com.bytz.common.util.mentity.util.MergeEntityOptions;
import com.bytz.common.util.mentity.util.MergeEntityUtil;
import com.bytz.modules.cms.c4c.model.C4cChineseName;
import com.bytz.modules.cms.c4c.service.IC4cFeignService;
import com.bytz.modules.cms.reseller.entity.EndUser;
import com.bytz.modules.cms.reseller.mapper.EndUserMapper;
import com.bytz.modules.cms.reseller.model.EndUserPage;
import com.bytz.modules.cms.reseller.service.IAdminEndUserService;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;
import java.util.stream.Stream;

@Service
public class AdminEndUserServiceImpl extends AbstractCrudService<EndUserMapper, EndUser, EndUser> implements IAdminEndUserService {

    @Autowired
    private IC4cFeignService c4cService;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean sync() {
        List<EndUser> newEndUsers = c4cService.getSoldToAndShipTo().stream()
                .filter(c4cCustomer -> StringUtils.isNotBlank(c4cCustomer.getExternalID()))
                .map(c4cCustomer -> {
                    EndUser endUser = new EndUser();
                    endUser.setAccountId(c4cCustomer.getAccountID());
                    endUser.setCustomerNumber(c4cCustomer.getExternalID());
                    endUser.setCustomerNameEn(c4cCustomer.getName());
                    endUser.setAddressEn(c4cCustomer.getFormattedPostalAddressDescription());
                    endUser.setPhone(c4cCustomer.getMobile());
                    endUser.setEmail(c4cCustomer.getEmail());
                    return endUser;
                }).collect(Collectors.toList());

        MergeEntityOptions<EndUser> options = MergeEntityOptions.<EndUser>builder()
                .keyExtractor(EndUser::getCustomerNumber)
                .updateEntityMerger((newEndUser, dbEndUser) -> {
                    newEndUser.setId(dbEndUser.getId());
                    // 如果c4c获取到的列表中发生了公司名或地址的改变，清空原先导入的公司名和地址，importFlag设置为0
                    if (!StringUtils.equals(newEndUser.getCustomerNameEn(), dbEndUser.getCustomerNameEn()) ||
                            !StringUtils.equals(newEndUser.getAddressEn(), dbEndUser.getAddressEn())) {
                        newEndUser.setAddress(newEndUser.getAddressEn());
                        newEndUser.setCustomerName(newEndUser.getCustomerNameEn());
                        newEndUser.setImportFlag(false);
                    }
                    if (BooleanUtil.isFalse(dbEndUser.getImportFlag()) || "-".equals(dbEndUser.getPhone())) {
                        newEndUser.setPhone(StringUtils.isBlank(newEndUser.getPhone()) ? "-" : newEndUser.getPhone());
                    }
                    return newEndUser;
                }).build();

        EntityMergeInfoV2<EndUser> mergeInfo = MergeEntityUtil.calculateEntityMergeInfo(newEndUsers, list(), options);

        mergeInfo.getAddEntities().forEach(endUser -> {
            endUser.setPhone(StringUtils.isBlank(endUser.getPhone()) ? "-" : endUser.getPhone());
            endUser.setContactPerson("-");
            endUser.setImportFlag(false);
            endUser.setAddress(endUser.getAddressEn());
            endUser.setCustomerName(endUser.getCustomerNameEn());
        });

        boolean update = updateBatchById(mergeInfo.getUpdateEntities());
        boolean save = saveBatch(mergeInfo.getAddEntities());
        return update && save;
    }

    /**
     * 同步终端用户的中文名称
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean syncChineseName() {
        List<EndUser> updateEndUsers = c4cService.getEndUserChineseName().stream()
                .filter(c4cChineseName -> StringUtils.isNotBlank(c4cChineseName.getAccountId()))
                // 有多个重复的accountId取第一个
                .collect(Collectors.toMap(C4cChineseName::getAccountId, name -> name, (existing, replacement) -> existing))
                .values().stream()
                .map(c4cChineseName -> {
                    EndUser endUser = new EndUser();
                    endUser.setAccountId(c4cChineseName.getAccountId());
                    endUser.setCustomerName(c4cChineseName.getBusinessPartnerFormattedName());
//                    String address = "Guangdong 广州 高新技术产业开发区 科学城开源大道11号 B4栋一至二层 510000";
                    String address = Stream.of(c4cChineseName.getStateCodeText().trim(), c4cChineseName.getCity().trim(), c4cChineseName.getDistrict().trim(), c4cChineseName.getAddressLine1().trim(), c4cChineseName.getStreet().trim(), c4cChineseName.getStreetPostalCode().trim())
                            .filter(s -> !s.isEmpty())
                            .collect(Collectors.joining(" "));
                    endUser.setAddress(address);
                    return endUser;
                }).collect(Collectors.toList());

        MergeEntityOptions<EndUser> options = MergeEntityOptions.<EndUser>builder()
                .keyExtractor(EndUser::getAccountId)
                .updateEntityMerger((updateEndUser, dbEndUser) -> {
                    updateEndUser.setId(dbEndUser.getId());
                    // 如果c4c获取到的列表中发生了公司名或地址的改变则更新
                    if (!StringUtils.equals(updateEndUser.getCustomerName(), dbEndUser.getCustomerName()) ||
                            !StringUtils.equals(updateEndUser.getAddress(), dbEndUser.getAddress())) {
                        return updateEndUser;
                    }
                    return null;
                }).build();

        EntityMergeInfoV2<EndUser> mergeInfo = MergeEntityUtil.calculateEntityMergeInfo(updateEndUsers, list(), options);


        return updateBatchById(mergeInfo.getUpdateEntities().stream().filter(Objects::nonNull).collect(Collectors.toList()));

    }

    @Override
    public EndUserPage<EndUser> queryPage(Page<EndUser> page, LambdaQueryWrapper<EndUser> queryWrapper) {

        Page<EndUser> endUserPage = page(page, queryWrapper);

        EndUserPage<EndUser> result = new EndUserPage<>();
        BeanUtils.copyProperties(endUserPage, result);

        result.setUpdateTime(getUpdateTime());

        return result;
    }

    @Override
    public List<EndUser> getImportFlagFalse() {
        return lambdaQuery().eq(EndUser::getImportFlag, false).list();
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void mergeDb(List<EndUser> list) {
        list.forEach(endUser -> endUser.setImportFlag(true));
        EntityMergeInfoV2<EndUser> mergeInfo = MergeEntityUtil.calculateEntityMergeInfo(
                list,
                list(),
                MergeEntityOptions.<EndUser>builder().keyExtractor(EndUser::getCustomerNumber).build()
        );
        saveBatch(mergeInfo.getAddEntities());
        updateBatchById(mergeInfo.getUpdateEntities());
    }

    @Override
    public List<EndUser> search(String numberLike) {

        if (StringUtils.isBlank(numberLike)) {
            return new ArrayList<>();
        }

        return lambdaQuery()
                .likeRight(EndUser::getCustomerNumber, numberLike)
                .list();
    }

    @Override
    protected EndUser insertSaveObject(EndUser saveRo) {
        save(saveRo);
        return saveRo;
    }

    @Override
    protected EndUser updateSaveObject(EndUser saveRo) {
        updateById(saveRo);
        return saveRo;
    }

    @Override
    protected EndUser saveOthers(EndUser saveRo) {
        return null;
    }

    @Override
    protected boolean deleteEntity(EndUser entity) {
        return removeById(entity.getId());
    }

    @Override
    protected void deleteOthers(EndUser entity) {

    }

    private LocalDateTime getUpdateTime() {

        EndUser newest = lambdaQuery()
                .select(EndUser::getUpdateTime)
                .orderByDesc(EndUser::getUpdateTime)
                .last("LIMIT 1")
                .one();

        if (newest != null) {

            return newest.getUpdateTime();
        }
        return null;
    }
}
